/*     */ package com.zimbra.cs.index;
/*     */ 
/*     */ import com.google.common.base.Joiner;
/*     */ import com.google.common.io.Closeables;
/*     */ import com.zimbra.common.service.ServiceException;
/*     */ import com.zimbra.common.soap.SoapProtocol;
/*     */ import com.zimbra.common.util.Log;
/*     */ import com.zimbra.common.util.ZimbraLog;
/*     */ import com.zimbra.cs.account.AccessManager;
/*     */ import com.zimbra.cs.account.Account;
/*     */ import com.zimbra.cs.index.query.ConjQuery;
/*     */ import com.zimbra.cs.index.query.ConjQuery.Conjunction;
/*     */ import com.zimbra.cs.index.query.InQuery;
/*     */ import com.zimbra.cs.index.query.Query;
/*     */ import com.zimbra.cs.index.query.Query.Modifier;
/*     */ import com.zimbra.cs.index.query.SubQuery;
/*     */ import com.zimbra.cs.index.query.parser.QueryParser;
/*     */ import com.zimbra.cs.mailbox.CalendarItem;
/*     */ import com.zimbra.cs.mailbox.Folder;
/*     */ import com.zimbra.cs.mailbox.MailItem;
/*     */ import com.zimbra.cs.mailbox.MailItem.Type;
/*     */ import com.zimbra.cs.mailbox.MailServiceException.NoSuchItemException;
/*     */ import com.zimbra.cs.mailbox.Mailbox;
/*     */ import com.zimbra.cs.mailbox.MailboxIndex;
/*     */ import com.zimbra.cs.mailbox.Mountpoint;
/*     */ import com.zimbra.cs.mailbox.OperationContext;
/*     */ import com.zimbra.cs.service.util.ItemId;
/*     */ import java.util.ArrayList;
/*     */ import java.util.HashSet;
/*     */ import java.util.Iterator;
/*     */ import java.util.List;
/*     */ import java.util.Set;
/*     */ import org.apache.lucene.index.Term;
/*     */ import org.apache.lucene.search.TermQuery;
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ public final class ZimbraQuery
/*     */ {
/*     */   private final List<Query> clauses;
/*     */   private QueryOperation operation;
/*     */   private final OperationContext octxt;
/*     */   private final SoapProtocol protocol;
/*     */   private final Mailbox mailbox;
/*     */   private final SearchParams params;
/*     */   private final ZimbraQuery.ParseTree.Node parseTree;
/*     */   
/*     */   private static class ParseTree
/*     */   {
/*     */     static enum Conjunction
/*     */     {
/*  91 */       AND,  OR;
/*     */       
/*     */       private Conjunction() {} }
/*     */     
/*  95 */     static abstract class Node { boolean bool = true;
/*     */       
/*     */ 
/*     */ 
/*     */       void setBool(boolean value)
/*     */       {
/* 101 */         this.bool = value;
/*     */       }
/*     */       
/*     */ 
/* 105 */       void invert() { this.bool = (!this.bool); }
/*     */       
/*     */       abstract void pushNotsDown();
/*     */       
/*     */       abstract Node simplify();
/*     */       
/*     */       abstract QueryOperation compile(Mailbox paramMailbox) throws ServiceException;
/*     */     }
/*     */     
/*     */     static class OperatorNode extends ZimbraQuery.ParseTree.Node { private ZimbraQuery.ParseTree.Conjunction conjunction;
/* 115 */       private List<ZimbraQuery.ParseTree.Node> nodes = new ArrayList();
/*     */       
/*     */       OperatorNode(ZimbraQuery.ParseTree.Conjunction conj) {
/* 118 */         this.conjunction = conj;
/*     */       }
/*     */       
/*     */       void pushNotsDown()
/*     */       {
/* 123 */         if (!this.bool) {
/* 124 */           this.bool = true;
/* 125 */           switch (ZimbraQuery.1.$SwitchMap$com$zimbra$cs$index$ZimbraQuery$ParseTree$Conjunction[this.conjunction.ordinal()]) {
/*     */           case 1: 
/* 127 */             this.conjunction = ZimbraQuery.ParseTree.Conjunction.OR;
/* 128 */             break;
/*     */           case 2: 
/* 130 */             this.conjunction = ZimbraQuery.ParseTree.Conjunction.AND;
/*     */           }
/*     */           
/* 133 */           for (ZimbraQuery.ParseTree.Node node : this.nodes) {
/* 134 */             node.invert();
/*     */           }
/*     */         }
/* 137 */         for (ZimbraQuery.ParseTree.Node node : this.nodes) {
/* 138 */           node.pushNotsDown();
/*     */         }
/*     */       }
/*     */       
/*     */       ZimbraQuery.ParseTree.Node simplify()
/*     */       {
/*     */         boolean simplifyAgain;
/*     */         do {
/* 146 */           simplifyAgain = false;
/*     */           
/* 148 */           List<ZimbraQuery.ParseTree.Node> simplified = new ArrayList();
/* 149 */           for (ZimbraQuery.ParseTree.Node node : this.nodes) {
/* 150 */             simplified.add(node.simplify());
/*     */           }
/* 152 */           this.nodes = simplified;
/*     */           
/*     */ 
/* 155 */           List<ZimbraQuery.ParseTree.Node> combined = new ArrayList();
/* 156 */           for (ZimbraQuery.ParseTree.Node node : this.nodes) {
/* 157 */             if ((node instanceof OperatorNode)) {
/* 158 */               OperatorNode opnode = (OperatorNode)node;
/* 159 */               if ((opnode.conjunction == this.conjunction) && (opnode.bool)) {
/* 160 */                 simplifyAgain = true;
/* 161 */                 for (ZimbraQuery.ParseTree.Node child : opnode.nodes) {
/* 162 */                   combined.add(child);
/*     */                 }
/* 164 */                 continue;
/*     */               }
/*     */             }
/* 167 */             combined.add(node);
/*     */           }
/* 169 */           this.nodes = combined;
/* 170 */         } while (simplifyAgain);
/*     */         
/* 172 */         if (this.nodes.isEmpty())
/* 173 */           return null;
/* 174 */         if (this.nodes.size() == 1) {
/* 175 */           ZimbraQuery.ParseTree.Node node = (ZimbraQuery.ParseTree.Node)this.nodes.get(0);
/* 176 */           if (!this.bool) {
/* 177 */             node.invert();
/*     */           }
/* 179 */           return node;
/*     */         }
/* 181 */         return this;
/*     */       }
/*     */       
/*     */       void add(ZimbraQuery.ParseTree.Node subNode) {
/* 185 */         this.nodes.add(subNode);
/*     */       }
/*     */       
/*     */       public List<ZimbraQuery.ParseTree.Node> getNodes() {
/* 189 */         return this.nodes;
/*     */       }
/*     */       
/*     */       public String toString()
/*     */       {
/* 194 */         StringBuilder buff = this.bool ? new StringBuilder() : new StringBuilder(" NOT ");
/* 195 */         buff.append(this.conjunction).append('[');
/* 196 */         Joiner.on(',').appendTo(buff, this.nodes);
/* 197 */         buff.append("] ");
/* 198 */         return buff.toString();
/*     */       }
/*     */       
/*     */       QueryOperation compile(Mailbox mbox) throws ServiceException
/*     */       {
/* 203 */         assert (this.bool);
/* 204 */         switch (ZimbraQuery.1.$SwitchMap$com$zimbra$cs$index$ZimbraQuery$ParseTree$Conjunction[this.conjunction.ordinal()]) {
/*     */         case 1: 
/* 206 */           IntersectionQueryOperation intersect = new IntersectionQueryOperation();
/* 207 */           for (ZimbraQuery.ParseTree.Node node : this.nodes) {
/* 208 */             QueryOperation op = node.compile(mbox);
/* 209 */             assert (op != null);
/* 210 */             intersect.addQueryOp(op);
/*     */           }
/* 212 */           return intersect;
/*     */         case 2: 
/* 214 */           UnionQueryOperation union = new UnionQueryOperation();
/* 215 */           for (ZimbraQuery.ParseTree.Node node : this.nodes) {
/* 216 */             QueryOperation op = node.compile(mbox);
/* 217 */             assert (op != null);
/* 218 */             union.add(op);
/*     */           }
/* 220 */           return union;
/*     */         }
/* 222 */         throw new IllegalStateException(this.conjunction.name());
/*     */       }
/*     */     }
/*     */     
/*     */     static class ThingNode extends ZimbraQuery.ParseTree.Node
/*     */     {
/*     */       private final Query query;
/*     */       
/*     */       ThingNode(Query query)
/*     */       {
/* 232 */         this.query = query;
/* 233 */         this.bool = query.getBool();
/*     */       }
/*     */       
/*     */ 
/*     */       void pushNotsDown() {}
/*     */       
/*     */ 
/*     */       ZimbraQuery.ParseTree.Node simplify()
/*     */       {
/* 242 */         return this;
/*     */       }
/*     */       
/*     */       public Query getQuery() {
/* 246 */         return this.query;
/*     */       }
/*     */       
/*     */       public void invert()
/*     */       {
/* 251 */         if ((this.query instanceof InQuery)) {
/* 252 */           if (this.query.getModifier() == Query.Modifier.MINUS) {
/* 253 */             this.query.setModifier(Query.Modifier.NONE);
/*     */           } else {
/* 255 */             this.query.setModifier(Query.Modifier.MINUS);
/*     */           }
/*     */         } else {
/* 258 */           super.invert();
/*     */         }
/*     */       }
/*     */       
/*     */       public String toString()
/*     */       {
/* 264 */         StringBuilder buff = this.bool ? new StringBuilder() : new StringBuilder(" NOT ");
/* 265 */         buff.append(this.query);
/* 266 */         return buff.toString();
/*     */       }
/*     */       
/*     */       QueryOperation compile(Mailbox mbox) throws ServiceException
/*     */       {
/* 271 */         return this.query.compile(mbox, this.bool);
/*     */       }
/*     */     }
/*     */     
/*     */     static Node build(List<Query> clauses) {
/* 276 */       OperatorNode top = new OperatorNode(Conjunction.OR);
/* 277 */       OperatorNode cur = new OperatorNode(Conjunction.AND);
/* 278 */       top.add(cur);
/*     */       
/* 280 */       for (Query query : clauses) {
/* 281 */         if ((query instanceof ConjQuery)) {
/* 282 */           if (((ConjQuery)query).getConjunction() == ConjQuery.Conjunction.OR) {
/* 283 */             cur = new OperatorNode(Conjunction.AND);
/* 284 */             top.add(cur);
/*     */           }
/* 286 */         } else if ((query instanceof SubQuery)) {
/* 287 */           SubQuery sq = (SubQuery)query;
/* 288 */           Node subTree = build(sq.getSubClauses());
/* 289 */           subTree.setBool(sq.getModifier() != Query.Modifier.MINUS);
/* 290 */           cur.add(subTree);
/*     */         } else {
/* 292 */           cur.add(new ThingNode(query));
/*     */         }
/*     */       }
/*     */       
/* 296 */       return top;
/*     */     }
/*     */   }
/*     */   
/*     */   private static final class CountTextOperations implements QueryOperation.RecurseCallback {
/* 301 */     int num = 0;
/*     */     
/*     */     public void recurseCallback(QueryOperation op)
/*     */     {
/* 305 */       if ((op instanceof LuceneQueryOperation)) {
/* 306 */         this.num += 1;
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */   private static final class CountCombiningOperations implements QueryOperation.RecurseCallback {
/* 312 */     int num = 0;
/*     */     
/*     */     public void recurseCallback(QueryOperation op)
/*     */     {
/* 316 */       if (((op instanceof CombiningQueryOperation)) && 
/* 317 */         (((CombiningQueryOperation)op).getNumSubOps() > 1)) {
/* 318 */         this.num += 1;
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */   public boolean hasTextOperation()
/*     */   {
/* 328 */     for (Query query : this.clauses) {
/* 329 */       if (query.hasTextOperation()) {
/* 330 */         return true;
/*     */       }
/*     */     }
/* 333 */     return false;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */   private int getTextOperationCount(QueryOperation op)
/*     */   {
/* 340 */     if (op == null) {
/* 341 */       return 0;
/*     */     }
/* 343 */     CountTextOperations count = new CountTextOperations(null);
/* 344 */     op.depthFirstRecurse(count);
/* 345 */     return count.num;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */   int countNontrivialCombiningOperations()
/*     */   {
/* 352 */     if (this.operation == null) {
/* 353 */       return 0;
/*     */     }
/* 355 */     CountCombiningOperations count = new CountCombiningOperations(null);
/* 356 */     this.operation.depthFirstRecurse(count);
/* 357 */     return count.num;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */   public ZimbraQuery(OperationContext octxt, SoapProtocol proto, Mailbox mbox, SearchParams params)
/*     */     throws ServiceException
/*     */   {
/* 365 */     this.octxt = octxt;
/* 366 */     this.protocol = proto;
/* 367 */     this.params = params;
/* 368 */     this.mailbox = mbox;
/*     */     
/*     */     try
/*     */     {
/* 372 */       QueryParser parser = new QueryParser(mbox, mbox.index.getAnalyzer());
/* 373 */       parser.setDefaultField(params.getDefaultField());
/* 374 */       parser.setTypes(params.getTypes());
/* 375 */       parser.setTimeZone(params.getTimeZone());
/* 376 */       parser.setLocale(params.getLocale());
/* 377 */       parser.setQuick(params.isQuick());
/* 378 */       this.clauses = parser.parse(params.getQueryString());
/*     */       
/* 380 */       if (parser.getSortBy() != null) {
/* 381 */         SortBy sort = SortBy.of(parser.getSortBy());
/* 382 */         if (sort == null) {
/* 383 */           throw ServiceException.PARSE_ERROR("INVALID_SORTBY: " + sort, null);
/*     */         }
/* 385 */         params.setSortBy(sort);
/*     */       }
/*     */     } catch (Error e) {
/* 388 */       throw ServiceException.PARSE_ERROR("PARSER_ERROR", e);
/*     */     }
/*     */     
/* 391 */     ZimbraLog.search.debug("%s,types=%s,sort=%s", new Object[] { this, params.getTypes(), params.getSortBy() });
/*     */     
/*     */ 
/*     */ 
/* 395 */     this.parseTree = ParseTree.build(this.clauses).simplify();
/* 396 */     this.parseTree.pushNotsDown();
/*     */     
/*     */ 
/* 399 */     switch (params.getSortBy().getKey())
/*     */     {
/*     */     case RCPT: 
/* 402 */       if (hasTextOperation()) {
/* 403 */         throw ServiceException.INVALID_REQUEST("Sort '" + params.getSortBy().name() + "' can't be used with text query.", null);
/*     */       }
/*     */       
/*     */ 
/*     */       break;
/*     */     }
/*     */     
/*     */     
/* 411 */     SearchParams.Cursor cursor = params.getCursor();
/* 412 */     if (cursor != null)
/*     */     {
/* 414 */       if ((params.getCursor().isIncludeOffset()) && (hasTextOperation())) {
/* 415 */         throw ServiceException.INVALID_REQUEST("cursor.includeOffset can't be used with text query.", null);
/*     */       }
/*     */       
/* 418 */       if (cursor.getSortValue() == null) {
/* 419 */         ZimbraLog.search.debug("Supplementing sortValue sort=%s,id=%s", new Object[] { params.getSortBy(), cursor.getItemId() });
/*     */         try {
/* 421 */           MailItem item = this.mailbox.getItemById(null, cursor.getItemId().getId(), MailItem.Type.UNKNOWN);
/* 422 */           switch (params.getSortBy().getKey()) {
/*     */           case NAME: 
/* 424 */             cursor.setSortValue(item.getName());
/* 425 */             break;
/*     */           case RCPT: 
/* 427 */             cursor.setSortValue(item.getSortRecipients());
/* 428 */             break;
/*     */           case SENDER: 
/* 430 */             cursor.setSortValue(item.getSortSender());
/* 431 */             break;
/*     */           case SIZE: 
/* 433 */             cursor.setSortValue(String.valueOf(item.getSize()));
/* 434 */             break;
/*     */           case SUBJECT: 
/* 436 */             cursor.setSortValue(item.getSortSubject());
/* 437 */             break;
/*     */           case PRIORITY: 
/* 439 */             cursor.setSortValue(LuceneFields.valueForPriority(item.getFlagBitmask()));
/* 440 */             break;
/*     */           case FLAG: 
/* 442 */             cursor.setSortValue(LuceneFields.valueForBooleanField(item.isFlagged()));
/* 443 */             break;
/*     */           case ATTACHMENT: 
/* 445 */             cursor.setSortValue(LuceneFields.valueForBooleanField(item.hasAttachment()));
/* 446 */             break;
/*     */           case DATE: 
/*     */           default: 
/* 449 */             cursor.setSortValue(String.valueOf(item.getDate()));
/*     */           }
/*     */         }
/*     */         catch (MailServiceException.NoSuchItemException e) {
/* 453 */           params.setCursor(null);
/*     */         }
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */   private void compile() throws ServiceException {
/* 460 */     assert (this.clauses != null);
/* 461 */     if (this.clauses.isEmpty()) {
/* 462 */       return;
/*     */     }
/*     */     
/*     */ 
/*     */ 
/* 467 */     this.operation = this.parseTree.compile(this.mailbox);
/* 468 */     ZimbraLog.search.debug("OP=%s", new Object[] { this.operation });
/*     */     
/*     */ 
/* 471 */     this.operation = this.operation.expandLocalRemotePart(this.mailbox);
/* 472 */     ZimbraLog.search.debug("AFTEREXP=%s", new Object[] { this.operation });
/*     */     
/*     */ 
/* 475 */     this.operation = this.operation.optimize(this.mailbox);
/* 476 */     ZimbraLog.search.debug("OPTIMIZED=%s", new Object[] { this.operation });
/* 477 */     if ((this.operation == null) || ((this.operation instanceof NoTermQueryOperation))) {
/* 478 */       this.operation = new NoResultsQueryOperation();
/* 479 */       return;
/*     */     }
/*     */     
/*     */ 
/* 483 */     Set<QueryTarget> targets = this.operation.getQueryTargets();
/* 484 */     assert (((this.operation instanceof UnionQueryOperation)) || (QueryTarget.getExplicitTargetCount(targets) <= 1));
/*     */     
/*     */ 
/* 487 */     UnionQueryOperation remoteOps = new UnionQueryOperation();
/* 488 */     UnionQueryOperation localOps = new UnionQueryOperation();
/*     */     
/* 490 */     if ((this.operation instanceof UnionQueryOperation)) {
/* 491 */       UnionQueryOperation union = (UnionQueryOperation)this.operation;
/*     */       
/* 493 */       for (QueryOperation op : union.operations) {
/* 494 */         Set<QueryTarget> set = op.getQueryTargets();
/*     */         
/*     */ 
/*     */ 
/* 498 */         assert (QueryTarget.getExplicitTargetCount(set) <= 1);
/*     */         
/*     */ 
/*     */ 
/*     */ 
/* 503 */         if (QueryTarget.hasExternalTarget(set)) {
/* 504 */           remoteOps.add(op);
/*     */         } else {
/* 506 */           localOps.add(op);
/*     */         }
/*     */       }
/*     */     }
/*     */     else {
/* 511 */       Set<QueryTarget> set = this.operation.getQueryTargets();
/*     */       
/*     */ 
/* 514 */       assert (QueryTarget.getExplicitTargetCount(set) <= 1);
/*     */       
/* 516 */       if (QueryTarget.hasExternalTarget(set)) {
/* 517 */         remoteOps.add(this.operation);
/*     */       } else {
/* 519 */         localOps.add(this.operation);
/*     */       }
/*     */     }
/*     */     
/*     */ 
/* 524 */     if (!remoteOps.operations.isEmpty())
/*     */     {
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/* 530 */       for (int i = remoteOps.operations.size() - 1; i >= 0; i--) {
/* 531 */         QueryOperation op = (QueryOperation)remoteOps.operations.get(i);
/* 532 */         Set<QueryTarget> set = op.getQueryTargets();
/*     */         
/*     */ 
/*     */ 
/* 536 */         assert (QueryTarget.getExplicitTargetCount(set) <= 1);
/*     */         
/*     */ 
/*     */ 
/*     */ 
/* 541 */         if (QueryTarget.hasExternalTarget(set)) {
/* 542 */           remoteOps.operations.remove(i);
/* 543 */           boolean foundOne = false;
/*     */           
/* 545 */           for (QueryOperation remoteOp : remoteOps.operations) {
/* 546 */             if (((remoteOp instanceof RemoteQueryOperation)) && 
/* 547 */               (((RemoteQueryOperation)remoteOp).tryAddOredOperation(op))) {
/* 548 */               foundOne = true;
/* 549 */               break;
/*     */             }
/*     */           }
/*     */           
/* 553 */           if (!foundOne) {
/* 554 */             RemoteQueryOperation remoteOp = new RemoteQueryOperation();
/* 555 */             remoteOp.tryAddOredOperation(op);
/* 556 */             remoteOps.operations.add(i, remoteOp);
/*     */           }
/*     */         }
/*     */       }
/*     */       
/*     */ 
/* 562 */       for (QueryOperation remoteOp : remoteOps.operations) {
/* 563 */         assert ((remoteOp instanceof RemoteQueryOperation));
/*     */         try {
/* 565 */           ((RemoteQueryOperation)remoteOp).setup(this.protocol, this.octxt.getAuthToken(), this.params);
/*     */         } catch (Exception e) {
/* 567 */           ZimbraLog.search.info("Ignoring %s during RemoteQuery generation for %s", new Object[] { e, remoteOps });
/*     */         }
/*     */       }
/*     */     }
/*     */     
/*     */ 
/* 573 */     if (!localOps.operations.isEmpty()) {
/* 574 */       ZimbraLog.search.debug("LOCAL_IN=%s", new Object[] { localOps });
/*     */       
/* 576 */       Account authAcct = this.octxt != null ? this.octxt.getAuthenticatedUser() : this.mailbox.getAccount();
/*     */       
/*     */ 
/* 579 */       boolean includeTrash = false;
/* 580 */       boolean includeSpam = false;
/* 581 */       if (this.params.inDumpster())
/*     */       {
/* 583 */         includeTrash = true;
/* 584 */         includeSpam = true;
/* 585 */         if (!this.mailbox.hasFullAdminAccess(this.octxt)) {
/* 586 */           long now = this.octxt != null ? this.octxt.getTimestamp() : System.currentTimeMillis();
/* 587 */           long mdate = now - authAcct.getDumpsterUserVisibleAge();
/* 588 */           IntersectionQueryOperation and = new IntersectionQueryOperation();
/* 589 */           DBQueryOperation db = new DBQueryOperation();
/* 590 */           db.addMDateRange(mdate, false, -1L, false, true);
/* 591 */           and.addQueryOp((QueryOperation)localOps.clone());
/* 592 */           and.addQueryOp(db);
/* 593 */           localOps.operations.clear();
/* 594 */           localOps.operations.add(and);
/*     */         }
/*     */       } else {
/* 597 */         includeTrash = authAcct.isPrefIncludeTrashInSearch();
/* 598 */         includeSpam = authAcct.isPrefIncludeSpamInSearch();
/*     */       }
/* 600 */       if ((!includeTrash) || (!includeSpam))
/*     */       {
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/* 606 */         if (parseTreeIncludesFolder(this.parseTree, 4)) {
/* 607 */           includeSpam = true;
/*     */         }
/* 609 */         if (parseTreeIncludesFolder(this.parseTree, 3)) {
/* 610 */           includeTrash = true;
/*     */         }
/*     */       }
/* 613 */       if ((!includeTrash) || (!includeSpam)) {
/* 614 */         List<QueryOperation> toAdd = new ArrayList();
/* 615 */         for (Iterator<QueryOperation> iter = localOps.operations.iterator(); iter.hasNext();) {
/* 616 */           QueryOperation cur = (QueryOperation)iter.next();
/* 617 */           if (!cur.hasSpamTrashSetting()) {
/* 618 */             QueryOperation newOp = cur.ensureSpamTrashSetting(this.mailbox, includeTrash, includeSpam);
/* 619 */             if (newOp != cur) {
/* 620 */               iter.remove();
/* 621 */               toAdd.add(newOp);
/*     */             }
/*     */           }
/*     */         }
/* 625 */         localOps.operations.addAll(toAdd);
/* 626 */         ZimbraLog.search.debug("LOCAL_AFTER_TRASH/SPAM/DUMPSTER=%s", new Object[] { localOps });
/*     */       }
/*     */       
/*     */ 
/* 630 */       boolean allowPrivateAccess = true;
/* 631 */       if (this.octxt != null) {
/* 632 */         allowPrivateAccess = AccessManager.getInstance().allowPrivateAccess(this.octxt.getAuthenticatedUser(), this.mailbox.getAccount(), this.octxt.isUsingAdminPrivileges());
/*     */       }
/*     */       
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/* 644 */       UnionQueryOperation clonedLocal = null;
/* 645 */       Set<Folder> hasFolderRightPrivateSet = new HashSet();
/*     */       
/*     */ 
/* 648 */       Set<MailItem.Type> types = this.params.getTypes();
/* 649 */       boolean hasCalendarType = (types.contains(MailItem.Type.APPOINTMENT)) || (types.contains(MailItem.Type.TASK));
/*     */       
/* 651 */       if ((hasCalendarType) && (!allowPrivateAccess) && (getTextOperationCount(localOps) > 0))
/*     */       {
/*     */ 
/*     */ 
/*     */ 
/* 656 */         Set<Folder> allVisibleFolders = this.mailbox.getVisibleFolders(this.octxt);
/* 657 */         if (allVisibleFolders == null) {
/* 658 */           allVisibleFolders = new HashSet();
/* 659 */           allVisibleFolders.addAll(this.mailbox.getFolderList(this.octxt, SortBy.NONE));
/*     */         }
/* 661 */         for (Folder f : allVisibleFolders) {
/* 662 */           if ((f.getType() == MailItem.Type.FOLDER) && (CalendarItem.allowPrivateAccess(f, authAcct, false)))
/*     */           {
/* 664 */             hasFolderRightPrivateSet.add(f);
/*     */           }
/*     */         }
/* 667 */         if (!hasFolderRightPrivateSet.isEmpty()) {
/* 668 */           clonedLocal = (UnionQueryOperation)localOps.clone();
/*     */         }
/*     */       }
/*     */       
/* 672 */       Set<Folder> visibleFolders = this.mailbox.getVisibleFolders(this.octxt);
/*     */       
/* 674 */       localOps = handleLocalPermissionChecks(localOps, visibleFolders, allowPrivateAccess);
/*     */       
/* 676 */       ZimbraLog.search.debug("LOCAL_AFTER_PERM_CHECKS=%s", new Object[] { localOps });
/*     */       
/* 678 */       if (!hasFolderRightPrivateSet.isEmpty()) {
/* 679 */         ZimbraLog.search.debug("CLONED_LOCAL_BEFORE_PERM=%s", new Object[] { clonedLocal });
/*     */         
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/* 685 */         clonedLocal = handleLocalPermissionChecks(clonedLocal, hasFolderRightPrivateSet, true);
/*     */         
/* 687 */         ZimbraLog.search.debug("CLONED_LOCAL_AFTER_PERM=%s", new Object[] { clonedLocal });
/*     */         
/*     */ 
/* 690 */         assert (clonedLocal.operations.size() == 1);
/*     */         
/* 692 */         QueryOperation optimizedClonedLocal = clonedLocal.optimize(this.mailbox);
/* 693 */         ZimbraLog.search.debug("CLONED_LOCAL_AFTER_OPTIMIZE=%s", new Object[] { optimizedClonedLocal });
/*     */         
/* 695 */         UnionQueryOperation withPrivateExcluded = localOps;
/* 696 */         localOps = new UnionQueryOperation();
/* 697 */         localOps.add(withPrivateExcluded);
/* 698 */         localOps.add(optimizedClonedLocal);
/*     */         
/* 700 */         ZimbraLog.search.debug("LOCAL_WITH_CLONED=%s", new Object[] { localOps });
/*     */       }
/*     */       
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/* 714 */       localOps = removeLocalQueriesForPseudoTags(localOps);
/*     */     }
/*     */     
/* 717 */     UnionQueryOperation union = new UnionQueryOperation();
/* 718 */     union.add(localOps);
/* 719 */     union.add(remoteOps);
/* 720 */     ZimbraLog.search.debug("BEFORE_FINAL_OPT=%s", new Object[] { union });
/* 721 */     this.operation = union.optimize(this.mailbox);
/*     */     
/* 723 */     ZimbraLog.search.debug("COMPILED=%s", new Object[] { this.operation });
/*     */   }
/*     */   
/*     */   private boolean parseTreeIncludesFolder(ZimbraQuery.ParseTree.Node node, int folderId) {
/* 727 */     if ((node instanceof ZimbraQuery.ParseTree.OperatorNode)) {
/* 728 */       for (ZimbraQuery.ParseTree.Node subNode : ((ZimbraQuery.ParseTree.OperatorNode)node).getNodes()) {
/* 729 */         if (parseTreeIncludesFolder(subNode, folderId)) {
/* 730 */           return true;
/*     */         }
/*     */       }
/* 733 */     } else if ((node instanceof ZimbraQuery.ParseTree.ThingNode)) {
/* 734 */       Query query = ((ZimbraQuery.ParseTree.ThingNode)node).getQuery();
/* 735 */       if ((query instanceof InQuery)) {
/* 736 */         Folder folder = ((InQuery)query).getFolder();
/* 737 */         return (folder.getId() == folderId) && (query.getModifier() != Query.Modifier.MINUS);
/*     */       }
/* 739 */       return false;
/*     */     }
/*     */     
/* 742 */     return false;
/*     */   }
/*     */   
/*     */   public SearchParams getParams() {
/* 746 */     return this.params;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */   public ZimbraQueryResults execute()
/*     */     throws ServiceException
/*     */   {
/* 755 */     compile();
/*     */     
/* 757 */     Set<QueryTarget> targets = this.operation.getQueryTargets();
/* 758 */     assert (((this.operation instanceof UnionQueryOperation)) || (QueryTarget.getExplicitTargetCount(targets) <= 1));
/* 759 */     assert ((targets.size() > 1) || (!QueryTarget.hasExternalTarget(targets)) || ((this.operation instanceof RemoteQueryOperation)));
/*     */     
/* 761 */     ZimbraLog.search.debug("OPERATION: %s", new Object[] { this.operation });
/*     */     
/* 763 */     int chunkSize = (int)Math.min(this.params.getOffset() + this.params.getLimit(), 1000L);
/* 764 */     ZimbraQueryResults results = null;
/*     */     try {
/* 766 */       results = this.operation.run(this.mailbox, this.params, chunkSize);
/* 767 */       FilteredQueryResults filtered; if (((this.params.getIncludeTagDeleted()) && (this.params.getIncludeTagMuted())) || ((this.params.getFetchMode() != SearchParams.Fetch.IDS) || (this.params.getAllowableTaskStatuses() != null)))
/*     */       {
/*     */ 
/* 770 */         filtered = new FilteredQueryResults(results, this.params);
/*     */         
/* 772 */         if (!this.params.getIncludeTagDeleted()) {
/* 773 */           filtered.setFilterTagDeleted(true);
/*     */         }
/* 775 */         if (!this.params.getIncludeTagMuted()) {
/* 776 */           filtered.setFilterTagMuted(true);
/*     */         }
/* 778 */         if (this.params.getAllowableTaskStatuses() != null)
/* 779 */           filtered.setAllowedTaskStatuses(this.params.getAllowableTaskStatuses());
/*     */       }
/* 781 */       return filtered;
/*     */     }
/*     */     catch (RuntimeException e)
/*     */     {
/* 785 */       Closeables.closeQuietly(results);
/* 786 */       Closeables.closeQuietly(this.operation);
/* 787 */       throw e;
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */   private static final class excludePrivateCalendarItems
/*     */     implements QueryOperation.RecurseCallback
/*     */   {
/*     */     public void recurseCallback(QueryOperation op)
/*     */     {
/* 798 */       if ((op instanceof LuceneQueryOperation)) {
/* 799 */         ((LuceneQueryOperation)op).addAndedClause(new TermQuery(new Term("l.field", "_calendaritemclass:private")), false);
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   private UnionQueryOperation removeLocalQueriesForPseudoTags(UnionQueryOperation union)
/*     */   {
/* 821 */     boolean changesMade = false;
/* 822 */     boolean replaceOp; for (int i = union.operations.size() - 1; i >= 0; i--) {
/* 823 */       QueryOperation op = (QueryOperation)union.operations.get(i);
/* 824 */       replaceOp = false;
/* 825 */       if ((op instanceof IntersectionQueryOperation)) {
/* 826 */         IntersectionQueryOperation intersection = (IntersectionQueryOperation)op;
/* 827 */         for (QueryOperation andedOp : intersection.operations) {
/* 828 */           if ((andedOp instanceof DBQueryOperation)) {
/* 829 */             DBQueryOperation dbqOp = (DBQueryOperation)andedOp;
/* 830 */             replaceOp = dbqOp.isSearchForNonexistentLocalTag(this.mailbox);
/* 831 */             if (replaceOp) {
/* 832 */               changesMade = true;
/* 833 */               union.operations.remove(i);
/* 834 */               union.operations.add(i, new NoResultsQueryOperation());
/*     */             }
/*     */           }
/*     */         }
/*     */       }
/*     */     }
/* 840 */     if (changesMade) {
/* 841 */       ZimbraLog.search.debug("LOCAL_AFTER_PRUNE_NONEXISTENT_TAG_SEARCH:%s", new Object[] { union });
/*     */     }
/* 843 */     return union;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   private static UnionQueryOperation handleLocalPermissionChecks(UnionQueryOperation union, Set<Folder> visibleFolders, boolean allowPrivateAccess)
/*     */   {
/* 856 */     for (int i = union.operations.size() - 1; i >= 0; i--) {
/* 857 */       QueryOperation op = (QueryOperation)union.operations.get(i);
/* 858 */       Set<QueryTarget> targets = op.getQueryTargets();
/*     */       
/*     */ 
/*     */ 
/* 862 */       assert (QueryTarget.getExplicitTargetCount(targets) <= 1);
/*     */       
/*     */ 
/*     */ 
/* 866 */       if (!QueryTarget.hasExternalTarget(targets))
/*     */       {
/* 868 */         if (!allowPrivateAccess) {
/* 869 */           op.depthFirstRecurse(new excludePrivateCalendarItems(null));
/*     */         }
/* 871 */         if (visibleFolders != null) {
/* 872 */           if (visibleFolders.isEmpty()) {
/* 873 */             union.operations.remove(i);
/* 874 */             ZimbraLog.search.debug("Query changed to NULL_QUERY_OPERATION, no visible folders");
/* 875 */             union.operations.add(i, new NoResultsQueryOperation());
/*     */           } else {
/* 877 */             union.operations.remove(i);
/*     */             
/*     */ 
/* 880 */             IntersectionQueryOperation intersect = new IntersectionQueryOperation();
/* 881 */             intersect.addQueryOp(op);
/*     */             
/* 883 */             UnionQueryOperation newUnion = new UnionQueryOperation();
/* 884 */             intersect.addQueryOp(newUnion);
/*     */             
/*     */ 
/* 887 */             Set<Folder> targetFolders = null;
/* 888 */             if ((op instanceof DBQueryOperation)) {
/* 889 */               DBQueryOperation dbOp = (DBQueryOperation)op;
/* 890 */               targetFolders = dbOp.getTargetFolders();
/*     */             }
/*     */             
/* 893 */             for (Folder folder : visibleFolders)
/*     */             {
/* 895 */               if ((!(folder instanceof Mountpoint)) || (((Mountpoint)folder).isLocal())) {
/* 896 */                 if ((targetFolders == null) || (targetFolders.size() <= 0) || (targetFolders.contains(folder)))
/*     */                 {
/*     */ 
/* 899 */                   DBQueryOperation newOp = new DBQueryOperation();
/* 900 */                   newUnion.add(newOp);
/* 901 */                   newOp.addInFolder(folder, true);
/*     */                 }
/*     */               }
/*     */             }
/* 905 */             union.operations.add(i, intersect);
/*     */           }
/*     */         }
/*     */       }
/*     */     }
/*     */     
/* 911 */     return union;
/*     */   }
/*     */   
/*     */   public String toString()
/*     */   {
/* 916 */     StringBuilder out = new StringBuilder("ZQ: ");
/* 917 */     for (Query clause : this.clauses) {
/* 918 */       clause.toString(out);
/*     */     }
/* 920 */     return out.toString();
/*     */   }
/*     */   
/*     */   public String toQueryString() throws ServiceException {
/* 924 */     if (this.operation == null) {
/* 925 */       compile();
/*     */     }
/* 927 */     return this.operation.toQueryString();
/*     */   }
/*     */   
/*     */   public String toSanitizedtring() throws ServiceException {
/* 931 */     StringBuilder out = new StringBuilder();
/* 932 */     for (Query clause : this.clauses) {
/* 933 */       clause.toSanitizedString(out);
/*     */     }
/* 935 */     return out.toString();
/*     */   }
/*     */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/index/ZimbraQuery.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */